home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / UNIX / C / INDENT / INDENT.C < prev    next >
C/C++ Source or Header  |  1989-09-05  |  47KB  |  1,458 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
  24.  @(#) Copyright (c) 1980 The Regents of the University of California.\n\
  25.  @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
  26.  All rights reserved.\n";
  27. #endif /* not lint */
  28.  
  29. #ifndef lint
  30. static char sccsid[] = "@(#)indent.c    5.11 (Berkeley) 9/15/88";
  31. #endif /* not lint */
  32.  
  33. #include "indent_globs.h"
  34. #include <ctype.h>
  35.  
  36. char       *in_name = 0;    /* will always point to name of input
  37.                      * file */
  38. char       *out_name = 0;    /* will always point to name
  39.                          * of output file */
  40.  
  41. /* The following variables are documented in indent_globs.h.  */
  42. int else_or_endif = false;
  43.  
  44. main(argc, argv)
  45.     int         argc;
  46.     char      **argv;
  47. {
  48.  
  49.     extern int  found_err;    /* flag set in diag() on error */
  50.  
  51.     int         dec_ind;    /* current indentation for declarations */
  52.     /* Pointer to a stack of structure indentation levels.
  53.        realloc'd as necessary.  */
  54.     int *di_stack;
  55.     /* Currently allocated size of di_stack.  */
  56.     int di_stack_alloc;
  57.     
  58.     int         flushed_nl;    /* used when buffering up comments to remember
  59.                  * that a newline was passed over */
  60.     int         force_nl;    /* when true, code must be broken */
  61.     enum codes  hd_type;    /* used to store type of stmt for if (...),
  62.                  * for (...), etc */
  63.     register int i;        /* local loop counter */
  64.     int         scase;        /* set to true when we see a case, so we will
  65.                  * know what to do with the following colon */
  66.     int         sp_sw;        /* when true, we are in the expressin of
  67.                  * if(...), while(...), etc. */
  68.  
  69.     /* True if we have just encountered the end of an if (...), etc.
  70.        (i.e. the ')' of the if (...) was the last token).  The variable
  71.        is set to 2 in the middle of the main token reading loop and is
  72.        decremented at the beginning of the loop, so it will reach zero
  73.        when the second token after the ')' is read.  */
  74.     int last_token_ends_sp = 0;
  75.     
  76.     int         squest;        /* when this is positive, we have seen a ?
  77.                  * without the matching : in a <c>?<s>:<s>
  78.                  * construct */
  79.     register char *t_ptr;    /* used for copying tokens */
  80.     enum codes type_code;    /* the type of token, returned by lexi */
  81.  
  82.     int         last_else = 0;    /* true iff last keyword was an else */
  83.  
  84.  
  85.     /*-----------------------------------------------*\
  86.     |              INITIALIZATION              |
  87.     \*-----------------------------------------------*/
  88.  
  89.     parser_state_tos = (struct parser_state *)
  90.       xmalloc(sizeof(struct parser_state));
  91.     parser_state_tos->next = 0;
  92.     /* Allocate initial stacks for the parser.  */
  93.     parser_state_tos->p_stack_size = INITIAL_STACK_SIZE;
  94.     parser_state_tos->p_stack = (enum codes *) xmalloc
  95.       (parser_state_tos->p_stack_size * sizeof (enum codes));
  96.     parser_state_tos->il = (int *) xmalloc
  97.       (parser_state_tos->p_stack_size * sizeof (int));
  98.     parser_state_tos->cstk = (int *) xmalloc
  99.       (parser_state_tos->p_stack_size * sizeof (int));
  100.  
  101.     parser_state_tos->paren_indents_size = 1;
  102.     parser_state_tos->paren_indents = (short *) xmalloc
  103.       (parser_state_tos->paren_indents_size * sizeof (short));
  104.     
  105.     parser_state_tos->p_stack[0] = stmt;    /* this is the parser's stack */
  106.     parser_state_tos->last_nl = true;        /* this is true if the last thing scanned was
  107.                  * a newline */
  108.     parser_state_tos->last_token = semicolon;
  109.     combuf = (char *) xmalloc(bufsize);
  110.     labbuf = (char *) xmalloc(bufsize);
  111.     codebuf = (char *) xmalloc(bufsize);
  112.     l_com = combuf + bufsize - 5;
  113.     l_lab = labbuf + bufsize - 5;
  114.     l_code = codebuf + bufsize - 5;
  115.     combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
  116.                          * comment buffers */
  117.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  118.     else_if = 1;        /* Default else-if special processing to on */
  119.     s_lab = e_lab = labbuf + 1;
  120.     s_code = e_code = codebuf + 1;
  121.     s_com = e_com = combuf + 1;
  122.  
  123.     init_buf(save_com);
  124.  
  125.     line_no = 1;
  126.     had_eof = parser_state_tos->in_decl = parser_state_tos->decl_on_line = break_comma = false;
  127.     sp_sw = force_nl = false;
  128.     parser_state_tos->in_or_st = false;
  129.     parser_state_tos->bl_line = true;
  130.     
  131.     dec_ind = 0;
  132.     di_stack_alloc = 2;
  133.     di_stack = (int *)xmalloc (di_stack_alloc * sizeof (*di_stack));
  134.     di_stack[parser_state_tos->dec_nest = 0] = 0;
  135.     
  136.     parser_state_tos->want_blank = parser_state_tos->in_stmt = parser_state_tos->ind_stmt = false;
  137.     parser_state_tos->procname = parser_state_tos->procname_end = "\0";
  138.  
  139.     scase = parser_state_tos->pcase = false;
  140.     squest = 0;
  141.     bp_save = 0;
  142.     be_save = 0;
  143.  
  144.     output = 0;
  145.  
  146.  
  147.  
  148.     /*--------------------------------------------------*\
  149.     |           COMMAND LINE SCAN         |
  150.     \*--------------------------------------------------*/
  151.  
  152.     for (i = 1; i < argc; ++i)
  153.     if (strcmp(argv[i], "-npro") == 0)
  154.         break;
  155.     set_defaults();
  156.     if (i >= argc)
  157.     set_profile();
  158.  
  159.     for (i = 1; i < argc; ++i) {
  160.  
  161.     /*
  162.      * look thru args (if any) for changes to defaults
  163.      */
  164.  
  165.     if (argv[i][0] != '-') {/* no flag on parameter */
  166.         if (in_name == 0) {    /* we must have the input file */
  167.         in_name = argv[i];    /* remember name of input file */
  168.         read_file(in_name);
  169.         continue;
  170.         }
  171.         else if (out_name == 0) {    /* we have the output file */
  172.         out_name = argv[i];    /* remember name of output file */
  173.         continue;
  174.         }
  175.         fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  176.         exit(1);
  177.     }
  178.     else
  179.         set_option(argv[i],1);
  180.     }                /* end of for */
  181.     if (in_name == 0) {
  182.         if (use_stdinout) {
  183.             read_stdin ();
  184.         in_name = "Standard input";
  185.     } else {
  186.         fprintf(stderr,
  187.             "indent: usage: indent file [ outfile ] [ options ]\n");
  188.         exit(1);
  189.     }
  190.     }
  191.     if (out_name)
  192.       {
  193.     if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
  194.                          * the file */
  195.       fprintf(stderr, "indent: input and output files must be different\n");
  196.       exit(1);
  197.     }
  198.     output = fopen(out_name, "w");
  199.     if (output == 0) {    /* check for create error */
  200.       fprintf(stderr, "indent: can't create %s\n", argv[i]);
  201.       exit(1);
  202.     }
  203.       }
  204.     if (output == 0)
  205.       {
  206.     if (use_stdinout || troff)
  207.         output = stdout;
  208.     else {
  209.         out_name = in_name;
  210.         bakcopy();
  211.     }
  212.       }
  213.     if (com_ind <= 1)
  214.     com_ind = 2;        /* dont put normal comments before column 2 */
  215.     if (troff) {
  216.     if (bodyf.font[0] == 0)
  217.         parsefont(&bodyf, "R");
  218.     if (scomf.font[0] == 0)
  219.         parsefont(&scomf, "I");
  220.     if (blkcomf.font[0] == 0)
  221.         blkcomf = scomf, blkcomf.size += 2;
  222.     if (boxcomf.font[0] == 0)
  223.         boxcomf = blkcomf;
  224.     if (stringf.font[0] == 0)
  225.         parsefont(&stringf, "L");
  226.     if (keywordf.font[0] == 0)
  227.         parsefont(&keywordf, "B");
  228.     writefdef(&bodyf, 'B');
  229.     writefdef(&scomf, 'C');
  230.     writefdef(&blkcomf, 'L');
  231.     writefdef(&boxcomf, 'X');
  232.     writefdef(&stringf, 'S');
  233.     writefdef(&keywordf, 'K');
  234.     }
  235.     if (block_comment_max_col <= 0)
  236.     block_comment_max_col = max_col;
  237.     if (decl_com_ind <= 0)    /* if not specified by user, set this */
  238.     decl_com_ind =
  239.       ljust_decl ? (com_ind <= 10 ? 2 : com_ind - 8) : com_ind;
  240.     if (continuation_indent == 0)
  241.     continuation_indent = ind_size;
  242.     fill_buffer();        /* get first batch of stuff into input buffer */
  243.  
  244.     parse(semicolon);
  245.     {
  246.     register char *p = buf_ptr;
  247.     register    col = 1;
  248.  
  249.     while (1) {
  250.         if (*p == ' ')
  251.         col++;
  252.         else if (*p == '\t')
  253.         col = ((col - 1) & ~7) + 9;
  254.         else
  255.         break;
  256.         p++;
  257.     }
  258.     if (col > ind_size)
  259.       parser_state_tos->ind_level = parser_state_tos->i_l_follow = col;
  260.     }
  261.     if (troff) {
  262.     register char *p = in_name,
  263.                *beg = in_name;
  264.  
  265.     while (*p)
  266.         if (*p++ == '/')
  267.         beg = p;
  268.     fprintf(output, ".Fn \"%s\"\n", beg);
  269.     }
  270.     /*
  271.      * START OF MAIN LOOP
  272.      */
  273.  
  274.     while (1) {            /* this is the main loop.  it will go until we
  275.                  * reach eof */
  276.     int         is_procname;
  277.  
  278.     type_code = lexi();    /* lexi reads one token.  "token" points to
  279.                    the actual characters. lexi
  280.                    returns a code indicating the type of token */
  281.  
  282.     if (last_token_ends_sp > 0)
  283.       last_token_ends_sp--;
  284.     is_procname = parser_state_tos->procname[0];
  285.  
  286.     /*
  287.      * The following code moves everything following an if (), while (),
  288.      * else, etc. up to the start of the following stmt to a buffer. This
  289.      * allows proper handling of both kinds of brace placement.
  290.      */
  291.  
  292.     flushed_nl = false;
  293.     while (parser_state_tos->search_brace)
  294.       {
  295.         /* After scanning an if(), while (), etc., it might be
  296.                necessary to keep track of the text between the if() and
  297.            the start of the statement which follows.  Use save_com
  298.            to do so.  */
  299.         
  300.         switch (type_code) {
  301.         case newline:
  302.         ++line_no;
  303.         flushed_nl = true;
  304.         case form_feed:
  305.         break;        /* form feeds and newlines found here will be
  306.                  * ignored */
  307.  
  308.         case lbrace:    /* this is a brace that starts the compound
  309.                  * stmt */
  310.         if (save_com.end == save_com.ptr) { /* ignore buffering if a comment wasnt
  311.                         stored up */
  312.             parser_state_tos->search_brace = false;
  313.             goto check_type;
  314.         }
  315.         /* We need to put the '{' back into save_com somewhere.  */
  316.         if (btype_2)
  317.           /* Put it at the beginning, e.g.
  318.            if (foo) {
  319.              / * comment here * /
  320.           */
  321.           
  322.           save_com.ptr[0] = '{';
  323.  
  324.         else
  325.           {
  326.             /* Put it at the end, e.g.
  327.                if (foo)
  328.                  / * comment here * /
  329.                    {
  330.                */
  331.  
  332.             /* Putting in this newline causes a dump_line
  333.                to occur right after the comment, thus
  334.                insuring that it will be put in the correct column.  */
  335.             *save_com.end++ = '\n';
  336.             *save_com.end++ = '{';
  337.           }
  338.  
  339.         /* Go to common code to get out of this loop.  */
  340.         goto sw_buffer;
  341.  
  342.         case comment:    /* we have a comment, so we must copy it into
  343.                  * the buffer */
  344.         if (!flushed_nl || save_com.end != save_com.ptr)
  345.           {
  346.             need_chars(save_com,10);
  347.             if (save_com.end == save_com.ptr) {    /* if this is the first comment, we
  348.                      * must set up the buffer */
  349.             save_com.ptr[0] = save_com.ptr[1] = ' ';
  350.             save_com.end = save_com.ptr + 2;
  351.             }
  352.             else {
  353.             *save_com.end++ = '\n';    /* add newline between
  354.                          * comments */
  355.             *save_com.end++ = ' ';
  356.             --line_no;
  357.             }
  358.             *save_com.end++ = '/';    /* copy in start of comment */
  359.             *save_com.end++ = '*';
  360.  
  361.             for (;;) {    /* loop until we get to the end of the comment */
  362.                 /* make sure there is room for this character and
  363.                (while we're at it) the '/' we might add
  364.                at the end of the loop. */
  365.                 need_chars(save_com,2);
  366.             *save_com.end = *buf_ptr++;
  367.             if (buf_ptr >= buf_end) {
  368.                 fill_buffer();
  369.                 if (had_eof) {
  370.                   diag(1, "Unclosed comment");
  371.                   exit(1);
  372.                 }
  373.             }
  374.  
  375.             if (*save_com.end++ == '*' && *buf_ptr == '/')
  376.                 break;    /* we are at end of comment */
  377.  
  378.             }
  379.             *save_com.end++ = '/';    /* add ending slash */
  380.             if (++buf_ptr >= buf_end)    /* get past / in buffer */
  381.             fill_buffer();
  382.             break;
  383.         }
  384.         default:        /* it is the start of a normal statment */
  385.         if (flushed_nl)    /* if we flushed a newline, make sure it is
  386.                  * put back */
  387.             force_nl = true;
  388.         if (type_code == sp_paren && *token == 'i'
  389.             && last_else && else_if
  390.             || type_code == sp_nparen && *token == 'e'
  391.             && e_code != s_code && e_code[-1] == '}')
  392.             force_nl = false;
  393.  
  394.         if (save_com.end == save_com.ptr) {    /* ignore buffering if comment wasnt
  395.                      * saved up */
  396.             parser_state_tos->search_brace = false;
  397.             goto check_type;
  398.         }
  399.         if (force_nl) {    /* if we should insert a nl here, put it into
  400.                  * the buffer */
  401.             force_nl = false;
  402.             --line_no;    /* this will be re-increased when the nl is
  403.                  * read from the buffer */
  404.             need_chars(save_com,2);
  405.             *save_com.end++ = '\n';
  406.             *save_com.end++ = ' ';
  407.             if (verbose && !flushed_nl)    /* print error msg if the line
  408.                          * was not already broken */
  409.             diag(0, "Line broken");
  410.             flushed_nl = false;
  411.         }
  412.         for (t_ptr = token; t_ptr < token_end; ++t_ptr)
  413.           {
  414.             need_chars(save_com,1);
  415.             *save_com.end++ = *t_ptr;    /* copy token into temp buffer */
  416.           }
  417.         parser_state_tos->procname = "\0";
  418.  
  419.     sw_buffer:
  420.         parser_state_tos->search_brace = false;    /* stop looking for start of
  421.                          * stmt */
  422.         bp_save = buf_ptr;    /* save current input buffer */
  423.         be_save = buf_end;
  424.         buf_ptr = save_com.ptr;    /* fix so that subsequent calls to
  425.                      * lexi will take tokens out of
  426.                      * save_com */
  427.         need_chars(save_com,1);
  428.         *save_com.end++ = ' ';/* add trailing blank, just in case */
  429.         buf_end = save_com.end;
  430.         save_com.end = save_com.ptr; /* make save_com empty */
  431.         break;
  432.         }            /* end of switch */
  433.         /* we must make this check, just in case there
  434.            was an unexpected EOF */
  435.         if (type_code != code_eof)
  436.         type_code = lexi();    /* read another token */
  437.         /* if (parser_state_tos->search_brace) parser_state_tos->procname[0] = 0; */
  438.         if ((is_procname = parser_state_tos->procname[0]) && flushed_nl
  439.             && !procnames_start_line && parser_state_tos->in_decl
  440.             && type_code == ident)
  441.         flushed_nl = 0;
  442.     }            /* end of while (search_brace) */
  443.     last_else = 0;
  444. check_type:
  445.     if (type_code == code_eof) {    /* we got eof */
  446.         if (s_lab != e_lab || s_code != e_code
  447.             || s_com != e_com)    /* must dump end of line */
  448.         dump_line();
  449.         if (parser_state_tos->tos > 1)    /* check for balanced braces */
  450.         diag(1, "Stuff missing from end of file.");
  451.  
  452.         if (verbose) {
  453.         printf("There were %d output lines and %d comments\n",
  454.                parser_state_tos->out_lines, parser_state_tos->out_coms);
  455.         printf("(Lines with comments)/(Lines with code): %6.3f\n",
  456.                (1.0 * parser_state_tos->com_lines) / code_lines);
  457.         }
  458.         fflush(output);
  459.         exit(found_err);
  460.     }
  461.     if (
  462.         (type_code != comment) &&
  463.         (type_code != newline) &&
  464.         (type_code != preesc) &&
  465.         (type_code != form_feed)) {
  466.         if (force_nl &&
  467.             (type_code != semicolon) &&
  468.             (type_code != lbrace || !btype_2)) {
  469.         /* we should force a broken line here */
  470.         if (verbose && !flushed_nl)
  471.             diag(0, "Line broken");
  472.         flushed_nl = false;
  473.         dump_line();
  474.         parser_state_tos->want_blank = false;    /* dont insert blank at line start */
  475.         force_nl = false;
  476.         }
  477.         parser_state_tos->in_stmt = true;    /* turn on flag which causes an extra level of
  478.                  * indentation. this is turned off by a ; or
  479.                  * '}' */
  480.         if (s_com != e_com) {    /* the turkey has embedded a comment
  481.                      * in a line. fix it */
  482.         *e_code++ = ' ';
  483.         for (t_ptr = s_com; *t_ptr; ++t_ptr) {
  484.             check_code_size;
  485.             *e_code++ = *t_ptr;
  486.         }
  487.         *e_code++ = ' ';
  488.         *e_code = '\0';    /* null terminate code sect */
  489.         parser_state_tos->want_blank = false;
  490.         e_com = s_com;
  491.         }
  492.     }
  493.     else if (type_code != comment)    /* preserve force_nl thru a comment */
  494.         force_nl = false;    /* cancel forced newline after newline, form
  495.                  * feed, etc */
  496.  
  497.  
  498.  
  499.     /*-----------------------------------------------------*\
  500.     |       do switch on type of token scanned        |
  501.     \*-----------------------------------------------------*/
  502.     check_code_size;
  503.     switch (type_code) {    /* now, decide what to do with the token */
  504.  
  505.     case form_feed:    /* found a form feed in line */
  506.         parser_state_tos->use_ff = true;    /* a form feed is treated much like a newline */
  507.         dump_line();
  508.         parser_state_tos->want_blank = false;
  509.         break;
  510.  
  511.     case newline:
  512.         if (parser_state_tos->last_token != comma || parser_state_tos->p_l_follow > 0
  513.             || !leave_comma || parser_state_tos->block_init || !break_comma || s_com != e_com) {
  514.         dump_line();
  515.         parser_state_tos->want_blank = false;
  516.         }
  517.         /* If we were on the line with a #else or a #endif,
  518.            we aren't anymore.  */
  519.         else_or_endif = false;
  520.         ++line_no;        /* keep track of input line number */
  521.         break;
  522.  
  523.     case lparen:
  524.         /* Braces in initializer lists should be put on new lines.
  525.            This is necessary so that -gnu does not cause things
  526.            like
  527.            char *this_is_a_string_array[] = {
  528.                                              "foo",
  529.                      "this_string_does_not_fit",
  530.                   "nor_does_this_rather_long_string"
  531.            }
  532.            which is what happens because we are trying to line
  533.            the strings up with the parentheses, and those that
  534.            are too long are moved to the right an ugly amount.
  535.  
  536.            However, if the current line is empty, the left brace
  537.            is already on a new line, so don't molest it.  */
  538.         if (token[0] == '{' &&
  539.         (s_code != e_code || s_com != e_com || s_lab != e_lab)
  540.         )
  541.           {
  542.         dump_line();
  543.         /* Do not put a space before the '{'.  */
  544.         parser_state_tos->want_blank = false;
  545.           }
  546.         
  547.         /* Count parens so we know how deep we are.  */
  548.         if (++parser_state_tos->p_l_follow
  549.         >= parser_state_tos->paren_indents_size)
  550.           {
  551.         parser_state_tos->paren_indents_size *= 2;
  552.         parser_state_tos->paren_indents = (short *)
  553.           xrealloc (parser_state_tos->paren_indents,
  554.                 parser_state_tos->paren_indents_size
  555.                   * sizeof (short));
  556.           }
  557.         if (parser_state_tos->want_blank && *token != '[' &&
  558.             (parser_state_tos->last_token != ident || proc_calls_space
  559.           || (parser_state_tos->its_a_keyword && (!parser_state_tos->sizeof_keyword || Bill_Shannon))))
  560.         *e_code++ = ' ';
  561.         if (parser_state_tos->in_decl && !parser_state_tos->block_init)
  562.         if (troff && !parser_state_tos->dumped_decl_indent && !is_procname && parser_state_tos->last_token == decl) {
  563.             parser_state_tos->dumped_decl_indent = 1;
  564.             sprintf (e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7,
  565.                  token_end - token, token);
  566.             e_code += strlen(e_code);
  567.         }
  568.         else {
  569.             while ((e_code - s_code) < dec_ind) {
  570.             check_code_size;
  571.             *e_code++ = ' ';
  572.             }
  573.             *e_code++ = token[0];
  574.         }
  575.         else
  576.         *e_code++ = token[0];
  577.         parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] = e_code - s_code;
  578.         if (sp_sw && parser_state_tos->p_l_follow == 1 && extra_expression_indent
  579.             && parser_state_tos->paren_indents[0] < 2 * ind_size)
  580.         parser_state_tos->paren_indents[0] = 2 * ind_size;
  581.         parser_state_tos->want_blank = false;
  582.         if (parser_state_tos->in_or_st && *token == '(' && parser_state_tos->tos <= 2) {
  583.         /*
  584.          * this is a kluge to make sure that declarations will be
  585.          * aligned right if proc decl has an explicit type on it, i.e.
  586.          * "int a(x) {..."
  587.          */
  588.         parse(semicolon);    /* I said this was a kluge... */
  589.         parser_state_tos->in_or_st = false;    /* turn off flag for structure decl or
  590.                      * initialization */
  591.         }
  592.         if (parser_state_tos->sizeof_keyword)
  593.         parser_state_tos->sizeof_mask |= 1 << parser_state_tos->p_l_follow;
  594.         break;
  595.  
  596.     case rparen:
  597.         if (parser_state_tos->cast_mask & (1 << parser_state_tos->p_l_follow) & ~parser_state_tos->sizeof_mask) {
  598.         parser_state_tos->last_u_d = true;
  599.         parser_state_tos->cast_mask &= (1 << parser_state_tos->p_l_follow) - 1;
  600.         }
  601.         parser_state_tos->sizeof_mask &= (1 << parser_state_tos->p_l_follow) - 1;
  602.         if (--parser_state_tos->p_l_follow < 0) {
  603.         parser_state_tos->p_l_follow = 0;
  604.         diag(0, "Extra %c", *token);
  605.         }
  606.         if (e_code == s_code)    /* if the paren starts the line */
  607.           {
  608.         parser_state_tos->paren_level = parser_state_tos->p_l_follow;    /* then indent it */
  609.         paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
  610.           }
  611.         *e_code++ = token[0];
  612.  
  613.         if (!parser_state_tos->cast_mask || cast_space)
  614.           parser_state_tos->want_blank = true;
  615.  
  616.         if (sp_sw && (parser_state_tos->p_l_follow == 0)) {    /* check for end of if
  617.                              * (...), or some such */
  618.             /* Indicate that we have just left the parenthesized
  619.            expression of a while, if, or for, unless
  620.            we are getting out of the parenthesized expression
  621.            of the while of a do-while loop.  (do-while is
  622.            different because a semicolon immediately following
  623.            this will not indicate a null loop body).  */
  624.             if (parser_state_tos->p_stack[parser_state_tos->tos]
  625.             != dohead)
  626.               last_token_ends_sp = 2;
  627.         sp_sw = false;
  628.         force_nl = true;/* must force newline after if */
  629.         parser_state_tos->last_u_d = true;    /* inform lexi that a following
  630.                      * operator is unary */
  631.         parser_state_tos->in_stmt = false;    /* dont use stmt continuation
  632.                      * indentation */
  633.  
  634.         parse(hd_type);    /* let parser worry about if, or whatever */
  635.         }
  636.         parser_state_tos->search_brace = btype_2;    /* this should insure that constructs
  637.                      * such as main(){...} and int[]{...}
  638.                      * have their braces put in the right
  639.                      * place */
  640.         break;
  641.  
  642.     case unary_op:        /* this could be any unary operation */
  643.         if (parser_state_tos->want_blank)
  644.         *e_code++ = ' ';
  645.  
  646.         if (troff && !parser_state_tos->dumped_decl_indent && parser_state_tos->in_decl && !is_procname) {
  647.         sprintf(e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7,
  648.             token_end - token, token);
  649.         parser_state_tos->dumped_decl_indent = 1;
  650.         e_code += strlen(e_code);
  651.         }
  652.         else {
  653.         char       *res = token;
  654.         char *res_end = token_end;
  655.  
  656.         if (parser_state_tos->in_decl && !parser_state_tos->block_init) {    /* if this is a unary op
  657.                              * in a declaration, we
  658.                              * should indent this
  659.                              * token */
  660.             while ((e_code - s_code) < (dec_ind - (token_end-token))) {
  661.             check_code_size;
  662.             *e_code++ = ' ';    /* pad it */
  663.             }
  664.         }
  665.         if (troff && token[0] == '-' && token[1] == '>')
  666.           {
  667.             static char resval[] = "\\(->";
  668.             res = resval;
  669.             res_end = res + sizeof(resval);
  670.           }
  671.         for (t_ptr = res; t_ptr < res_end; ++t_ptr) {
  672.             check_code_size;
  673.             *e_code++ = *t_ptr;
  674.         }
  675.         }
  676.         parser_state_tos->want_blank = false;
  677.         break;
  678.  
  679.     case binary_op:    /* any binary operation */
  680.         if (parser_state_tos->want_blank)
  681.         *e_code++ = ' ';
  682.         {
  683.         char       *res = token;
  684.         char *res_end = token_end;
  685. #define set_res(str) \
  686.           {\
  687.         static char resval[] = str;\
  688.         res = resval;\
  689.         res_end = res + sizeof(resval);\
  690.           }
  691.  
  692.         if (troff)
  693.             switch (token[0]) {
  694.             case '<':
  695.             if (token[1] == '=')
  696.               set_res ("\\(<=");
  697.             break;
  698.             case '>':
  699.             if (token[1] == '=')
  700.                 set_res ("\\(>=");
  701.             break;
  702.             case '!':
  703.             if (token[1] == '=')
  704.                 set_res ("\\(!=");
  705.             break;
  706.             case '|':
  707.             if (token[1] == '|')
  708.               {
  709.                 set_res ("\\(br\\(br");
  710.               }
  711.             else if (token[1] == 0)
  712.                 set_res ("\\(br");
  713.             break;
  714.             }
  715.         for (t_ptr = res; t_ptr < res_end; ++t_ptr) {
  716.             check_code_size;
  717.             *e_code++ = *t_ptr;    /* move the operator */
  718.         }
  719.         }
  720.         parser_state_tos->want_blank = true;
  721.         break;
  722.  
  723.     case postop:        /* got a trailing ++ or -- */
  724.         *e_code++ = token[0];
  725.         *e_code++ = token[1];
  726.         parser_state_tos->want_blank = true;
  727.         break;
  728.  
  729.     case question:        /* got a ? */
  730.         squest++;        /* this will be used when a later colon
  731.                  * appears so we can distinguish the
  732.                  * <c>?<n>:<n> construct */
  733.         if (parser_state_tos->want_blank)
  734.         *e_code++ = ' ';
  735.         *e_code++ = '?';
  736.         parser_state_tos->want_blank = true;
  737.         break;
  738.  
  739.     case casestmt:        /* got word 'case' or 'default' */
  740.         scase = true;    /* so we can process the later colon properly */
  741.         goto copy_id;
  742.  
  743.     case colon:        /* got a ':' */
  744.         if (squest > 0) {    /* it is part of the <c>?<n>: <n> construct */
  745.         --squest;
  746.         if (parser_state_tos->want_blank)
  747.             *e_code++ = ' ';
  748.         *e_code++ = ':';
  749.         parser_state_tos->want_blank = true;
  750.         break;
  751.         }
  752.         if (parser_state_tos->in_decl) {
  753.         *e_code++ = ':';
  754.         parser_state_tos->want_blank = false;
  755.         break;
  756.         }
  757.         parser_state_tos->in_stmt = false;    /* seeing a label does not imply we are in a
  758.                  * stmt */
  759.         for (t_ptr = s_code; *t_ptr; ++t_ptr)
  760.         *e_lab++ = *t_ptr;    /* turn everything so far into a label */
  761.         e_code = s_code;
  762.         *e_lab++ = ':';
  763.         *e_lab++ = ' ';
  764.         *e_lab = '\0';
  765.  
  766.         force_nl = parser_state_tos->pcase = scase;    /* parser_state_tos->pcase will be used by
  767.                          * dump_line to decide how to
  768.                          * indent the label. force_nl
  769.                          * will force a case n: to be
  770.                          * on a line by itself */
  771.         scase = false;
  772.         parser_state_tos->want_blank = false;
  773.         break;
  774.  
  775.     case semicolon:    /* got a ';' */
  776.         parser_state_tos->in_or_st = false;/* we are not in an initialization or
  777.                  * structure declaration */
  778.         scase = false;    /* these will only need resetting in a error */
  779.         squest = 0;
  780.         /* The following code doesn't seem to do much good.
  781.            Just because we've found something like
  782.            extern int foo();    or
  783.            int (*foo)();
  784.            doesn't mean we are out of a declaration.  Now if it was
  785.            serving some purpose we'll have to address that....
  786.         if (parser_state_tos->last_token == rparen)
  787.         parser_state_tos->in_parameter_declaration = 0;
  788.         */
  789.         parser_state_tos->cast_mask = 0;
  790.         parser_state_tos->sizeof_mask = 0;
  791.         parser_state_tos->block_init = 0;
  792.         parser_state_tos->block_init_level = 0;
  793.         parser_state_tos->just_saw_decl--;
  794.  
  795.         if (parser_state_tos->in_decl && s_code == e_code && !parser_state_tos->block_init)
  796.         while ((e_code - s_code) < (dec_ind - 1)) {
  797.             check_code_size;
  798.             *e_code++ = ' ';
  799.         }
  800.  
  801.         parser_state_tos->in_decl = (parser_state_tos->dec_nest > 0);    /* if we were in a first level
  802.                          * structure declaration, we
  803.                          * arent any more */
  804.  
  805.         if ((!sp_sw || hd_type != forstmt) && parser_state_tos->p_l_follow > 0) {
  806.  
  807.         /*
  808.          * This should be true iff there were unbalanced parens in the
  809.          * stmt.  It is a bit complicated, because the semicolon might
  810.          * be in a for stmt
  811.          */
  812.         diag(1, "Unbalanced parens");
  813.         parser_state_tos->p_l_follow = 0;
  814.         if (sp_sw) {    /* this is a check for a if, while, etc. with
  815.                  * unbalanced parens */
  816.             sp_sw = false;
  817.             parse(hd_type);    /* dont lose the if, or whatever */
  818.         }
  819.         }
  820.  
  821.         /* If we have a semicolon following an if, while, or for,
  822.            and the user wants us to, we should insert a space
  823.            (to show that there is a null statement there).  */
  824.         if (last_token_ends_sp && space_sp_semicolon)
  825.           {
  826.         *e_code++ = ' ';
  827.           }
  828.         *e_code++ = ';';
  829.         parser_state_tos->want_blank = true;
  830.         parser_state_tos->in_stmt = (parser_state_tos->p_l_follow > 0);    /* we are no longer in the
  831.                          * middle of a stmt */
  832.  
  833.         if (!sp_sw) {    /* if not if for (;;) */
  834.         parse(semicolon);    /* let parser know about end of stmt */
  835.         force_nl = true;/* force newline after a end of stmt */
  836.         }
  837.         break;
  838.  
  839.     case lbrace:        /* got a '{' */
  840.         parser_state_tos->in_stmt = false;    /* dont indent the {} */
  841.         if (!parser_state_tos->block_init)
  842.         force_nl = true;/* force other stuff on same line as '{' onto
  843.                  * new line */
  844.         else if (parser_state_tos->block_init_level <= 0)
  845.         parser_state_tos->block_init_level = 1;
  846.         else
  847.         parser_state_tos->block_init_level++;
  848.  
  849.         if (s_code != e_code && !parser_state_tos->block_init) {
  850.         if (!btype_2) {
  851.             dump_line();
  852.             parser_state_tos->want_blank = false;
  853.         }
  854.         else if (parser_state_tos->in_parameter_declaration && !parser_state_tos->in_or_st) {
  855.             parser_state_tos->i_l_follow = 0;
  856.             dump_line();
  857.             parser_state_tos->want_blank = false;
  858.         }
  859.         }
  860.         if (parser_state_tos->in_parameter_declaration)
  861.         prefix_blankline_requested = 0;
  862.  
  863.         if (parser_state_tos->p_l_follow > 0) {    /* check for preceeding unbalanced
  864.                      * parens */
  865.         diag(1, "Unbalanced parens");
  866.         parser_state_tos->p_l_follow = 0;
  867.         if (sp_sw) {    /* check for unclosed if, for, etc. */
  868.             sp_sw = false;
  869.             parse(hd_type);
  870.             parser_state_tos->ind_level = parser_state_tos->i_l_follow;
  871.         }
  872.         }
  873.         if (s_code == e_code)
  874.         parser_state_tos->ind_stmt = false;    /* dont put extra indentation on line
  875.                      * with '{' */
  876.         if (parser_state_tos->in_decl && parser_state_tos->in_or_st)
  877.           {
  878.         /* This is a structure declaration.  */
  879.             if (parser_state_tos->dec_nest >= di_stack_alloc)
  880.           {
  881.             di_stack_alloc *= 2;
  882.             di_stack = (int *)
  883.               xrealloc (di_stack,
  884.                 di_stack_alloc * sizeof (*di_stack));
  885.           }
  886.         di_stack[parser_state_tos->dec_nest++] = dec_ind;
  887.         /* ?        dec_ind = 0; */
  888.         }
  889.         else {
  890.         parser_state_tos->decl_on_line = false;    /* we cant be in the middle of
  891.                          * a declaration, so dont do
  892.                          * special indentation of
  893.                          * comments */
  894.         if (blanklines_after_declarations_at_proctop
  895.             && parser_state_tos->in_parameter_declaration)
  896.             postfix_blankline_requested = 1;
  897.         parser_state_tos->in_parameter_declaration = 0;
  898.         }
  899.         dec_ind = 0;
  900.  
  901.         /* We are no longer looking for an initializer or structure.
  902.            Needed so that the '=' in "enum bar {a = 1" does not
  903.            get interpreted as the start of an initializer.  */
  904.         parser_state_tos->in_or_st = false;
  905.            
  906.         parse(lbrace);    /* let parser know about this */
  907.         if (parser_state_tos->want_blank)    /* put a blank before '{' if '{' is not at
  908.                  * start of line */
  909.         *e_code++ = ' ';
  910.         parser_state_tos->want_blank = false;
  911.         *e_code++ = '{';
  912.         parser_state_tos->just_saw_decl = 0;
  913.         break;
  914.  
  915.     case rbrace:        /* got a '}' */
  916.         if (parser_state_tos->p_stack[parser_state_tos->tos] == decl && !parser_state_tos->block_init)    /* semicolons can be
  917.                                  * omitted in
  918.                                  * declarations */
  919.         parse(semicolon);
  920.         if (parser_state_tos->p_l_follow) {/* check for unclosed if, for, else. */
  921.         diag(1, "Unbalanced parens");
  922.         parser_state_tos->p_l_follow = 0;
  923.         sp_sw = false;
  924.         }
  925.         parser_state_tos->just_saw_decl = 0;
  926.         parser_state_tos->block_init_level--;
  927.         if (s_code != e_code && !parser_state_tos->block_init) {    /* '}' must be first on
  928.                              * line */
  929.         if (verbose)
  930.             diag(0, "Line broken");
  931.         dump_line();
  932.         }
  933.         *e_code++ = '}';
  934.         parser_state_tos->want_blank = true;
  935.         parser_state_tos->in_stmt = parser_state_tos->ind_stmt = false;
  936.         if (parser_state_tos->dec_nest > 0) {    /* we are in multi-level structure
  937.                      * declaration */
  938.         dec_ind = di_stack[--parser_state_tos->dec_nest];
  939.         if (parser_state_tos->dec_nest == 0 && !parser_state_tos->in_parameter_declaration)
  940.             parser_state_tos->just_saw_decl = 2;
  941.         parser_state_tos->in_decl = true;
  942.         }
  943.         prefix_blankline_requested = 0;
  944.         parse(rbrace);    /* let parser know about this */
  945.         parser_state_tos->search_brace = cuddle_else && parser_state_tos->p_stack[parser_state_tos->tos] == ifhead
  946.         && parser_state_tos->il[parser_state_tos->tos] >= parser_state_tos->ind_level;
  947.         if (parser_state_tos->tos <= 1 && blanklines_after_procs && parser_state_tos->dec_nest <= 0)
  948.         postfix_blankline_requested = 1;
  949.         break;
  950.  
  951.     case swstmt:        /* got keyword "switch" */
  952.         sp_sw = true;
  953.         hd_type = swstmt;    /* keep this for when we have seen the
  954.                  * expression */
  955.         goto copy_id;    /* go move the token into buffer */
  956.  
  957.     case sp_paren:        /* token is if, while, for */
  958.         sp_sw = true;    /* the interesting stuff is done after the
  959.                  * expression is scanned */
  960.         hd_type = (*token == 'i' ? ifstmt :
  961.                (*token == 'w' ? whilestmt : forstmt));
  962.  
  963.         /*
  964.          * remember the type of header for later use by parser
  965.          */
  966.         goto copy_id;    /* copy the token into line */
  967.  
  968.     case sp_nparen:    /* got else, do */
  969.         parser_state_tos->in_stmt = false;
  970.         if (*token == 'e') {
  971.         if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
  972.             if (verbose)
  973.             diag(0, "Line broken");
  974.             dump_line();/* make sure this starts a line */
  975.             parser_state_tos->want_blank = false;
  976.         }
  977.         force_nl = true;/* also, following stuff must go onto new line */
  978.         last_else = 1;
  979.         parse(elselit);
  980.         }
  981.         else {
  982.         if (e_code != s_code) {    /* make sure this starts a line */
  983.             if (verbose)
  984.             diag(0, "Line broken");
  985.             dump_line();
  986.             parser_state_tos->want_blank = false;
  987.         }
  988.         force_nl = true;/* also, following stuff must go onto new line */
  989.         last_else = 0;
  990.         parse(dolit);
  991.         }
  992.         goto copy_id;    /* move the token into line */
  993.  
  994.     case decl:        /* we have a declaration type (int, register,
  995.                  * etc.) */
  996.         parse(decl);    /* let parser worry about indentation */
  997.         if (parser_state_tos->last_token == rparen && parser_state_tos->tos <= 1) {
  998.         parser_state_tos->in_parameter_declaration = 1;
  999.         if (s_code != e_code) {
  1000.             dump_line();
  1001.             parser_state_tos->want_blank = 0;
  1002.         }
  1003.         }
  1004.         if (parser_state_tos->in_parameter_declaration && indent_parameters && parser_state_tos->dec_nest == 0) {
  1005.         parser_state_tos->ind_level = parser_state_tos->i_l_follow = indent_parameters;
  1006.         parser_state_tos->ind_stmt = 0;
  1007.         }
  1008.         parser_state_tos->in_or_st = true;    /* this might be a structure or initialization
  1009.                  * declaration */
  1010.         parser_state_tos->in_decl = parser_state_tos->decl_on_line = true;
  1011.         if ( /* !parser_state_tos->in_or_st && */ parser_state_tos->dec_nest <= 0)
  1012.         parser_state_tos->just_saw_decl = 2;
  1013.         prefix_blankline_requested = 0;
  1014.         i = token_end - token + 1;    /* get length of token plus 1 */
  1015.  
  1016.         /*
  1017.          * dec_ind = e_code - s_code + (parser_state_tos->decl_indent>i ? parser_state_tos->decl_indent
  1018.          * : i);
  1019.          */
  1020.         dec_ind = decl_indent > 0 ? decl_indent : i;
  1021.         goto copy_id;
  1022.  
  1023.     case ident:        /* got an identifier or constant */
  1024.         if (parser_state_tos->in_decl) {    /* if we are in a declaration, we must indent
  1025.                  * identifier */
  1026.         if (parser_state_tos->want_blank)
  1027.             *e_code++ = ' ';
  1028.         parser_state_tos->want_blank = false;
  1029.         if (is_procname == 0 || !procnames_start_line) {
  1030.             if (!parser_state_tos->block_init)
  1031.             if (troff && !parser_state_tos->dumped_decl_indent) {
  1032.                 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
  1033.                 parser_state_tos->dumped_decl_indent = 1;
  1034.                 e_code += strlen(e_code);
  1035.             }
  1036.             else
  1037.                 while ((e_code - s_code) < dec_ind) {
  1038.                 check_code_size;
  1039.                 *e_code++ = ' ';
  1040.                 }
  1041.         }
  1042.         else {
  1043.             if (dec_ind && s_code != e_code)
  1044.             dump_line();
  1045.             dec_ind = 0;
  1046.             parser_state_tos->want_blank = false;
  1047.         }
  1048.         }
  1049.         else if (sp_sw && parser_state_tos->p_l_follow == 0) {
  1050.         sp_sw = false;
  1051.         force_nl = true;
  1052.         parser_state_tos->last_u_d = true;
  1053.         parser_state_tos->in_stmt = false;
  1054.         parse(hd_type);
  1055.         }
  1056.     copy_id:
  1057.         if (parser_state_tos->want_blank)
  1058.         *e_code++ = ' ';
  1059.         if (troff && parser_state_tos->its_a_keyword) {
  1060.         e_code = chfont(&bodyf, &keywordf, e_code);
  1061.         for (t_ptr = token; t_ptr < token_end; ++t_ptr) {
  1062.             check_code_size;
  1063.             *e_code++ = keywordf.allcaps && islower(*t_ptr)
  1064.             ? toupper(*t_ptr) : *t_ptr;
  1065.         }
  1066.         e_code = chfont(&keywordf, &bodyf, e_code);
  1067.         }
  1068.         else
  1069.           {
  1070.         /* Troff mode requires that strings be processed specially.  */
  1071.         if (troff && (*token == '"' || *token == '\''))
  1072.           {
  1073.             char qchar;
  1074.  
  1075.             qchar = *token;
  1076.             *e_code++ = '`';
  1077.             if (qchar == '"')
  1078.               *e_code++ = '`';
  1079.             e_code = chfont(&bodyf, &stringf, e_code);
  1080.  
  1081.             t_ptr = token + 1;
  1082.             while (t_ptr < token_end)
  1083.               {
  1084.             *e_code = *t_ptr++;
  1085.             if (*e_code == '\\')
  1086.               {
  1087.                 *++e_code = '\\';
  1088.                 if (*t_ptr == '\\')
  1089.                   *++e_code = '\\';
  1090.                 /* Copy char after backslash.  */
  1091.                 *++e_code = *t_ptr++;
  1092.                 /* Point after the last char we copied.  */
  1093.                 e_code++;
  1094.               }
  1095.               }
  1096.             e_code = chfont(&stringf, &bodyf, e_code - 1);
  1097.             if (qchar == '"')
  1098.               *e_code++ = '\'';
  1099.           }
  1100.         else
  1101.           for (t_ptr = token; t_ptr < token_end; ++t_ptr)
  1102.             {
  1103.               check_code_size;
  1104.               *e_code++ = *t_ptr;
  1105.             }
  1106.         }    
  1107.         parser_state_tos->want_blank = true;
  1108.  
  1109.         /* If the token is va_dcl, it appears without a semicolon,
  1110.            so we need to pretend that one was there.  */
  1111.         if ((token_end - token) == 6
  1112.         && strncmp(token,"va_dcl",6) == 0)
  1113.           {
  1114.         parser_state_tos->in_or_st = false;
  1115.         parser_state_tos->just_saw_decl--;
  1116.         parser_state_tos->in_decl = 0;
  1117.         parse(semicolon);
  1118.         force_nl = true;
  1119.           }
  1120.         break;
  1121.  
  1122.     case period:        /* treat a period kind of like a binary
  1123.                  * operation */
  1124.         *e_code++ = '.';    /* move the period into line */
  1125.         parser_state_tos->want_blank = false;    /* dont put a blank after a period */
  1126.         break;
  1127.  
  1128.     case comma:
  1129.         parser_state_tos->want_blank = (s_code != e_code);    /* only put blank after comma
  1130.                          * if comma does not start the
  1131.                          * line */
  1132.         if (parser_state_tos->in_decl && is_procname == 0 && !parser_state_tos->block_init)
  1133.         while ((e_code - s_code) < (dec_ind - 1)) {
  1134.             check_code_size;
  1135.             *e_code++ = ' ';
  1136.         }
  1137.  
  1138.         *e_code++ = ',';
  1139.         if (parser_state_tos->p_l_follow == 0) {
  1140.         if (parser_state_tos->block_init_level <= 0)
  1141.             parser_state_tos->block_init = 0;
  1142.         /* If we are in a declaration, and either the
  1143.            user wants all comma'd declarations broken,
  1144.            or the line is getting too long, break the line.  */
  1145.         if (break_comma &&
  1146.             (!leave_comma
  1147.              || (compute_code_target() + (e_code - s_code)
  1148.              > max_col - 8)
  1149.              ))
  1150.             force_nl = true;
  1151.         }
  1152.         break;
  1153.  
  1154.     case preesc:        /* got the character '#' */
  1155.         if ((s_com != e_com) ||
  1156.             (s_lab != e_lab) ||
  1157.             (s_code != e_code))
  1158.         dump_line();
  1159.         *e_lab++ = '#';    /* move whole line to 'label' buffer */
  1160.         {
  1161.         int         in_comment = 0;
  1162.         int         com_start = 0;
  1163.         char        quote = 0;
  1164.         int         com_end = 0;
  1165.  
  1166.         /* ANSI allows spaces between '#' and preprocessor
  1167.            directives.  Remove such spaces.  */
  1168.         while (*buf_ptr == ' ' || *buf_ptr == '\t') {
  1169.             buf_ptr++;
  1170.             if (buf_ptr >= buf_end)
  1171.             fill_buffer();
  1172.         }
  1173.         while (*buf_ptr != '\n' || in_comment) {
  1174.             check_lab_size;
  1175.             *e_lab = *buf_ptr++;
  1176.             if (buf_ptr >= buf_end)
  1177.             fill_buffer();
  1178.             switch (*e_lab++) {
  1179.             case BACKSLASH:
  1180.             if (troff)
  1181.                 *e_lab++ = BACKSLASH;
  1182.             if (!in_comment) {
  1183.                 *e_lab++ = *buf_ptr++;
  1184.                 if (buf_ptr >= buf_end)
  1185.                 fill_buffer();
  1186.             }
  1187.             break;
  1188.             case '/':
  1189.             if (*buf_ptr == '*' && !in_comment && !quote) {
  1190.                 in_comment = 1;
  1191.                 *e_lab++ = *buf_ptr++;
  1192.                 com_start = e_lab - s_lab - 2;
  1193.             }
  1194.             break;
  1195.             case '"':
  1196.             if (quote == '"')
  1197.                 quote = 0;
  1198.             break;
  1199.             case '\'':
  1200.             if (quote == '\'')
  1201.                 quote = 0;
  1202.             break;
  1203.             case '*':
  1204.             if (*buf_ptr == '/' && in_comment) {
  1205.                 in_comment = 0;
  1206.                 *e_lab++ = *buf_ptr++;
  1207.                 com_end = e_lab - s_lab;
  1208.             }
  1209.             break;
  1210.             }
  1211.         }
  1212.  
  1213.         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1214.             e_lab--;
  1215.         if (e_lab - s_lab == com_end && bp_save == 0) {    /* comment on
  1216.                                  * preprocessor line */
  1217.             if (save_com.end != save_com.ptr)
  1218.               {
  1219.                 need_chars(save_com,2);
  1220.             *save_com.end++ = '\n';    /* add newline between
  1221.                          * comments */
  1222.             *save_com.end++ = ' ';
  1223.             --line_no;
  1224.               }
  1225.             need_chars(save_com,com_end - com_start);
  1226.             strncpy (save_com.end, s_lab + com_start,
  1227.                  com_end - com_start);
  1228.             save_com.end += com_end - com_start;
  1229.  
  1230.             e_lab = s_lab + com_start;
  1231.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1232.             e_lab--;
  1233.             bp_save = buf_ptr;    /* save current input buffer */
  1234.             be_save = buf_end;
  1235.             buf_ptr = save_com.ptr;    /* fix so that subsequent calls to
  1236.                      * lexi will take tokens out of
  1237.                      * save_com */
  1238.             need_chars(save_com,1);
  1239.             *save_com.end++ = ' ';    /* add trailing blank, just in case */
  1240.             buf_end = save_com.end;
  1241.             save_com.end = save_com.ptr; /* make save_com empty */
  1242.         }
  1243.         *e_lab = '\0';    /* null terminate line */
  1244.         parser_state_tos->pcase = false;
  1245.         }
  1246.  
  1247.         if (strncmp(s_lab + 1, "if", 2) == 0) {
  1248.         if (blanklines_around_conditional_compilation) {
  1249.             register    c;
  1250.             prefix_blankline_requested++;
  1251.             while ((c = *in_prog_pos++) == '\n');
  1252.             in_prog_pos--;
  1253.         }
  1254.         {
  1255.           /* Push a copy of the parser_state onto the stack.
  1256.              All manipulations will use the copy at the top of stack,
  1257.              and then we
  1258.              can return to the previous state by popping the
  1259.              stack.  */
  1260.           struct parser_state *new;
  1261.  
  1262.           new = (struct parser_state *)
  1263.             xmalloc(sizeof(struct parser_state));
  1264.           mymemcpy (new, parser_state_tos, sizeof(struct parser_state));
  1265.  
  1266.           /* We need to copy the dynamically allocated arrays in
  1267.              the struct parser_state too.  */
  1268.           new->p_stack = (enum codes *)
  1269.             xmalloc (parser_state_tos->p_stack_size
  1270.                  * sizeof (enum codes));
  1271.           mymemcpy (new->p_stack, parser_state_tos->p_stack,
  1272.               parser_state_tos->p_stack_size * sizeof (enum codes));
  1273.  
  1274.           new->il = (int *)
  1275.             xmalloc (parser_state_tos->p_stack_size * sizeof (int));
  1276.           mymemcpy (new->il, parser_state_tos->il,
  1277.               parser_state_tos->p_stack_size * sizeof (int));
  1278.  
  1279.           new->cstk = (int *)
  1280.             xmalloc (parser_state_tos->p_stack_size
  1281.                  * sizeof (int));
  1282.           mymemcpy (new->cstk, parser_state_tos->cstk,
  1283.               parser_state_tos->p_stack_size * sizeof (int));
  1284.  
  1285.           new->paren_indents = (short *)xmalloc
  1286.             (parser_state_tos->paren_indents_size * sizeof (short));
  1287.           mymemcpy (new->paren_indents, parser_state_tos->paren_indents,
  1288.               parser_state_tos->paren_indents_size * sizeof (short));
  1289.           
  1290.           new->next = parser_state_tos;
  1291.           parser_state_tos = new;
  1292.         }
  1293.         }
  1294.         else if (strncmp(s_lab + 1, "else", 4) == 0)
  1295.           {
  1296.         /* When we get #else, we want to restore the parser
  1297.            state to what it was before the matching #if, so
  1298.            that things get lined up with the code before the
  1299.            #if.  However, we do not want to pop the stack; we
  1300.            just want to copy the second to top elt of the
  1301.            stack because when we encounter the #endif, it will
  1302.            pop the stack.  */
  1303.         else_or_endif = true;
  1304.         if (parser_state_tos->next)
  1305.           {
  1306.             /* First save the addresses of the arrays
  1307.                for the top of stack.  */
  1308.             enum codes *tos_p_stack = parser_state_tos->p_stack;
  1309.             int *tos_il = parser_state_tos->il;
  1310.             int *tos_cstk = parser_state_tos->cstk;
  1311.             short *tos_paren_indents =
  1312.               parser_state_tos->paren_indents;
  1313.             struct parser_state *second =
  1314.               parser_state_tos->next;
  1315.  
  1316.             mymemcpy (parser_state_tos, second,
  1317.                 sizeof(struct parser_state));
  1318.             parser_state_tos->next = second;
  1319.             
  1320.             /* Now copy the arrays from the second to top of
  1321.                stack to the top of stack.  */
  1322.             /* Since the p_stack, etc. arrays only grow, never
  1323.                shrink, we know that they will be big enough to
  1324.                fit the array from the second to top of stack.  */
  1325.             parser_state_tos->p_stack = tos_p_stack;
  1326.             mymemcpy (parser_state_tos->p_stack,
  1327.                 parser_state_tos->next->p_stack,
  1328.                 parser_state_tos->p_stack_size
  1329.                   * sizeof (enum codes));
  1330.  
  1331.             parser_state_tos->il = tos_il;
  1332.             mymemcpy (parser_state_tos->il,
  1333.                 parser_state_tos->next->il,
  1334.                 parser_state_tos->p_stack_size * sizeof (int));
  1335.  
  1336.             parser_state_tos->cstk = tos_cstk;
  1337.             mymemcpy (parser_state_tos->cstk,
  1338.                 parser_state_tos->next->cstk,
  1339.                 parser_state_tos->p_stack_size * sizeof (int));
  1340.  
  1341.             parser_state_tos->paren_indents = tos_paren_indents;
  1342.             mymemcpy (parser_state_tos->paren_indents,
  1343.                 parser_state_tos->next->paren_indents,
  1344.                 parser_state_tos->paren_indents_size
  1345.                   * sizeof (short));
  1346.           }
  1347.         else
  1348.             diag(1, "Unmatched #else");
  1349.           }
  1350.         else if (strncmp(s_lab + 1, "endif", 5) == 0)
  1351.           {
  1352.         else_or_endif = true;
  1353.         /* We want to remove the second to top elt on the
  1354.            stack, which was put there by #if and was used to
  1355.            restore the stack at the #else (if there was one).
  1356.            We want to leave the top of stack
  1357.            unmolested so that the state which we have been
  1358.            using is unchanged.  */
  1359.         if (parser_state_tos->next)
  1360.           {
  1361.             struct parser_state *second = parser_state_tos->next;
  1362.  
  1363.             parser_state_tos->next = second->next;
  1364.             free (second->p_stack);
  1365.             free (second->il);
  1366.             free (second->cstk);
  1367.             free (second->paren_indents);
  1368.             free (second);
  1369.           }
  1370.         else
  1371.             diag(1, "Unmatched #endif");
  1372.         if (blanklines_around_conditional_compilation) {
  1373.             postfix_blankline_requested++;
  1374.             n_real_blanklines = 0;
  1375.         }
  1376.           }
  1377.         break;        /* subsequent processing of the newline
  1378.                  * character will cause the line to be printed */
  1379.  
  1380.     case comment:        /* we have gotten a /*  this is a biggie */
  1381.         if (flushed_nl) {    /* we should force a broken line here */
  1382.         flushed_nl = false;
  1383.         dump_line();
  1384.         parser_state_tos->want_blank = false;    /* dont insert blank at line start */
  1385.         force_nl = false;
  1386.         }
  1387.         pr_comment();
  1388.         break;
  1389.     }            /* end of big switch stmt */
  1390.  
  1391.     *e_code = '\0';        /* make sure code section is null terminated */
  1392.     if (type_code != comment
  1393.         && type_code != newline
  1394.         && type_code != preesc
  1395.         && type_code != form_feed)
  1396.       parser_state_tos->last_token = type_code;
  1397.  
  1398.       }                /* end of main while (1) loop */
  1399. }
  1400.  
  1401. /*
  1402.  * copy input file to backup file if in_name is /blah/blah/blah/file, then
  1403.  * backup file will be "file.BAK" then make the backup file the input and
  1404.  * original input file the output
  1405.  */
  1406. bakcopy()
  1407. {
  1408.     /* file descriptor for the output file */
  1409.     int bakchn;
  1410.  
  1411.     /* Used to walk around file names */
  1412.     register char *p;
  1413.  
  1414.     /* Buffer for error message.  */
  1415.     char *errbuf;
  1416.     /* Backup file name.  */
  1417.     char *bakfile;
  1418.     
  1419.     /* construct name of backup file */
  1420.     for (p = in_name; *p; p++);    /* skip to end of string */
  1421.     while (p > in_name && *p != '/')    /* find last '/' */
  1422.     p--;
  1423.     if (*p == '/')
  1424.     p++;
  1425.     bakfile = xmalloc(40 + strlen(p));
  1426.     sprintf(bakfile, "%s.BAK", p);
  1427.     errbuf = xmalloc(80 + strlen(p));
  1428.  
  1429.     sprintf(errbuf,"indent: %s",bakfile);
  1430.       
  1431.     /* copy in_name to backup file */
  1432.     /* permissions 0666 means rw-rw-rw- (modified by umask).  */
  1433.     bakchn = creat(bakfile, 0666);
  1434.     if (bakchn < 0)
  1435.       {
  1436.     perror(errbuf);
  1437.     exit(1);
  1438.       }
  1439.  
  1440.     if (write(bakchn, in_prog, in_prog_size) != in_prog_size)
  1441.       {
  1442.     perror(errbuf);
  1443.     exit(1);
  1444.       }
  1445.  
  1446.     close(bakchn);
  1447.     
  1448.     /* now the original input file will be the output */
  1449.     output = fopen(in_name, "w");
  1450.     if (output == 0) {
  1451.     fprintf(stderr, "indent: can't create %s\n", in_name);
  1452.     unlink(bakfile);
  1453.     exit(1);
  1454.     }
  1455.     free (errbuf);
  1456.     free (bakfile);
  1457. }
  1458.